package se.gala.gametypes;

import java.util.HashSet;

import se.gala.core.M3GMatrix;
import se.gala.core.M3GMove;
import se.gala.core.abstracts.AbstractDrawSymbol;
import se.gala.core.abstracts.GameWithFixedOdds;
import se.gala.core.abstracts.PrecisionDegree;
import se.gala.utils.Coordinate2D;

public abstract class Match3Game extends GameWithFixedOdds {
	protected static enum Coordinate {X, Y};
	private boolean autoBurnAvailable = false;

	protected Match3Game(int symbolCount) {
		super(symbolCount);
	}

	public Match3Game(int symbolCount, PrecisionDegree precision) {
		super(symbolCount, precision);
	}

	public Match3Game(long historicRNGSeed, int symbolCount, PrecisionDegree precision) {
		super(historicRNGSeed, symbolCount, precision);
	}

	@Override
	public void playGame() {
		doInitialDraw();
	}
	
	/**
	 * Checks if there are any legals move left.
	 * @return
	 */
	public boolean checkForLegalMoves() {
		return getLegalMoves(true, false).size() > 0;
	}
	
	/**
	 * Checks what are the legal moves within the gemMatrix.
	 * 
	 * @param returnFirstResultOnly
	 *            Set this to <code>true</code> if it's important to check only
	 *            for presence of legal moves. This would improve performance.
	 * @param setWins
	 *            Set this to <code>true</code> if it's important to know the
	 *            outcome of the move. Otherwise keep it <code>false</code> due
	 *            to performance reasons.
	 * @return A collection of the legal moves.
	 */
	public abstract HashSet<M3GMove> getLegalMoves(boolean returnFirstResultOnly,
			boolean setWins);

	/**
	 * Checks if there are any winning combinations in the current matrix.
	 * @return
	 */
	public abstract boolean checkForWinnings();

	/**
	 * Checks if moving a symbol is a valid move (i.e. is it generate winnings, or not).
	 * @param oldLocation The current location of the symbol.
	 * @param newLocation The new location of the symbol.
	 * @param s The symbol to move.
	 * @return The result of the check.
	 */
	public abstract boolean isMoveLegal(Coordinate2D oldLocation, Coordinate2D newLocation, AbstractDrawSymbol s);
	
	/**
	 * Updates the m3gMatrix by removing the winning symbols and repositioning the others when necessary.
	 */
	public abstract void burnWinnings();
	
	final protected boolean checkWinningCombinationWhileShuffle(int x, int y, AbstractDrawSymbol s) {
		final M3GMatrix m = getMatrix();
		/* We count on x and y to come in the natural order */
		if (x >= 2) {
			final AbstractDrawSymbol s1 = M3GMatrix.getElementAt(x-1, y, m);
			final AbstractDrawSymbol s2 = M3GMatrix.getElementAt(x-2, y, m);
			if (s.equalTo(s1) && s.equalTo(s2)) {
				return true;
			}
		}
		if (y >= 2) {
			final AbstractDrawSymbol s3 = M3GMatrix.getElementAt(x, y-1, m);
			final AbstractDrawSymbol s4 = M3GMatrix.getElementAt(x, y-2, m);
			if (s.equalTo(s3) && s.equalTo(s4)) {
				return true;
			}
		}
		return false;
	}
	
	protected boolean setAutoburnAvailable(boolean autoBurnAvailable) {
		return this.autoBurnAvailable = autoBurnAvailable;
	}
	
	public boolean isAutoburnAvailable() {
		return autoBurnAvailable;
	}
	
	public abstract M3GMatrix getMatrix();
	public abstract void initDumpRecords();
}
